#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
响应解析器

该模块提供了解析HTTP响应的工具类，支持各种常见的响应格式解析。

创建时间: 2023-07-15
作者: Python Tools Team
"""

import json
import xml.etree.ElementTree as ET
from typing import Dict, Any, Optional, Union, List, Callable, Type, TypeVar, Generic
from dataclasses import dataclass

from .http_client import HttpResponse
from .exception import ResponseException

# 类型变量定义
T = TypeVar('T')  # 解析结果类型


class ResponseParser(Generic[T]):
    """
    响应解析器类
    
    提供了将HTTP响应解析为各种格式的方法。
    """
    
    @staticmethod
    def parse_json(response: HttpResponse) -> Dict[str, Any]:
        """
        将响应解析为JSON字典
        
        Args:
            response: HTTP响应对象
            
        Returns:
            Dict[str, Any]: 解析后的JSON字典
            
        Raises:
            ResponseException: 如果响应不是有效的JSON格式或状态码不是2xx
        """
        response.raise_for_status()
        return response.json()
    
    @staticmethod
    def parse_json_list(response: HttpResponse) -> List[Dict[str, Any]]:
        """
        将响应解析为JSON列表
        
        Args:
            response: HTTP响应对象
            
        Returns:
            List[Dict[str, Any]]: 解析后的JSON列表
            
        Raises:
            ResponseException: 如果响应不是有效的JSON列表格式或状态码不是2xx
        """
        response.raise_for_status()
        result = response.json()
        if not isinstance(result, list):
            raise ResponseException(
                message="响应不是有效的JSON列表格式",
                code="E100203",
                response=response._response
            )
        return result
    
    @staticmethod
    def parse_text(response: HttpResponse) -> str:
        """
        将响应解析为文本
        
        Args:
            response: HTTP响应对象
            
        Returns:
            str: 响应文本
            
        Raises:
            ResponseException: 如果状态码不是2xx
        """
        response.raise_for_status()
        return response.text
    
    @staticmethod
    def parse_xml(response: HttpResponse) -> ET.Element:
        """
        将响应解析为XML
        
        Args:
            response: HTTP响应对象
            
        Returns:
            ET.Element: 解析后的XML根元素
            
        Raises:
            ResponseException: 如果响应不是有效的XML格式或状态码不是2xx
        """
        response.raise_for_status()
        try:
            return ET.fromstring(response.text)
        except ET.ParseError as e:
            raise ResponseException(
                message="响应不是有效的XML格式",
                code="E100204",
                cause=e,
                response=response._response
            )
    
    @staticmethod
    def parse_binary(response: HttpResponse) -> bytes:
        """
        将响应解析为二进制数据
        
        Args:
            response: HTTP响应对象
            
        Returns:
            bytes: 响应二进制数据
            
        Raises:
            ResponseException: 如果状态码不是2xx
        """
        response.raise_for_status()
        return response.content
    
    @staticmethod
    def parse_with_model(response: HttpResponse, model_class: Type[T]) -> T:
        """
        将响应解析为指定模型类的实例
        
        Args:
            response: HTTP响应对象
            model_class: 模型类，必须支持从字典初始化
            
        Returns:
            T: 模型类实例
            
        Raises:
            ResponseException: 如果响应不是有效的JSON格式或状态码不是2xx
            TypeError: 如果模型类不支持从字典初始化
        """
        response.raise_for_status()
        data = response.json()
        
        try:
            # 尝试使用模型类从字典创建实例
            if hasattr(model_class, 'from_dict'):
                return model_class.from_dict(data)
            elif hasattr(model_class, 'parse_obj'):  # Pydantic 支持
                return model_class.parse_obj(data)
            else:
                return model_class(**data)
        except Exception as e:
            raise ResponseException(
                message=f"无法将响应解析为{model_class.__name__}模型",
                code="E100205",
                cause=e,
                response=response._response
            )
    
    @staticmethod
    def parse_with_function(response: HttpResponse, parser_func: Callable[[HttpResponse], T]) -> T:
        """
        使用自定义函数解析响应
        
        Args:
            response: HTTP响应对象
            parser_func: 解析函数，接受HttpResponse参数，返回解析结果
            
        Returns:
            T: 解析结果
            
        Raises:
            ResponseException: 如果状态码不是2xx或解析过程中发生错误
        """
        response.raise_for_status()
        try:
            return parser_func(response)
        except Exception as e:
            if isinstance(e, ResponseException):
                raise
            raise ResponseException(
                message="自定义解析函数执行失败",
                code="E100206",
                cause=e,
                response=response._response
            )
    
    @staticmethod
    def check_success_field(response: HttpResponse, success_field: str = 'success', success_value: Any = True) -> bool:
        """
        检查响应JSON中的成功标志字段
        
        Args:
            response: HTTP响应对象
            success_field: 成功标志字段名
            success_value: 表示成功的字段值
            
        Returns:
            bool: 如果成功标志字段存在且值等于success_value则返回True，否则返回False
            
        Raises:
            ResponseException: 如果响应不是有效的JSON格式
        """
        try:
            data = response.json()
            return success_field in data and data[success_field] == success_value
        except ValueError as e:
            raise ResponseException(
                message="响应不是有效的JSON格式",
                code="E100201",
                cause=e,
                response=response._response
            )
    
    @staticmethod
    def extract_field(response: HttpResponse, field_path: str, default: Optional[Any] = None) -> Any:
        """
        从响应JSON中提取指定路径的字段值
        
        Args:
            response: HTTP响应对象
            field_path: 字段路径，使用点号分隔，例如 'data.items.0.id'
            default: 如果字段不存在，返回的默认值
            
        Returns:
            Any: 字段值，如果字段不存在则返回默认值
            
        Raises:
            ResponseException: 如果响应不是有效的JSON格式
        """
        try:
            data = response.json()
            parts = field_path.split('.')
            
            for part in parts:
                if isinstance(data, list):
                    try:
                        index = int(part)
                        if 0 <= index < len(data):
                            data = data[index]
                        else:
                            return default
                    except ValueError:
                        return default
                elif isinstance(data, dict):
                    if part in data:
                        data = data[part]
                    else:
                        return default
                else:
                    return default
            
            return data
        except ValueError as e:
            raise ResponseException(
                message="响应不是有效的JSON格式",
                code="E100201",
                cause=e,
                response=response._response
            )